home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
misc
/
emu
/
Apex-src.lha
/
APEX.XPL
< prev
next >
Wrap
Text File
|
2001-09-30
|
56KB
|
2,316 lines
\APEX.XPL FEB-25-89 VERSION 1.8-X18
\COPYRIGHT 1980-1989, P.J.R. BOYLE.
\REVISION HISTORY:
\NOV-DEC-85, V1.8, 96 FILES MAX, AND NUMEROUS OTHER MODS, LOREN BLANEY.
\MAR-11-86, MODIFIED FOR THE 68000, L.B. (MARKED %%%)
\SEP-DEC-86, MODIFIED FOR NEW SYSTEM PAGE LAYOUT.
\MAR-13-87, CHANGED "SY" COMMAND FOR AMIGA AND FIXED MISC. LITTLE BUGS, L.B.
\APR-09-87, CHANGED STRING AND BLIT CONVENTIONS.
\FEB-25-89, ADDED OPENO(0) TO MAIN AND REMOVED OPENI(0) IN MAIN LOOP
\
\NOTES:
\This version is loaded using LOADX (LOAD residing at $3000). The WS command
\ is obsolete. These are the commands:
\
\ LOADX APEX
\ CHANGE DEFAULTS (N/Y)? Y
\ 76800
\ 76800
\ 7C000
\ 76800
\ NO
\ CTRL-P
\ SAVE SYSTEM.SYS
\
\The 68000 version retains the directory structure from the 6502 version.
\Note that the 16-bit values appear to have their bytes swapped to the 68000.
\
\In this code the word "device" is often used synonymously with "unit".
\The messages have been tailored for the Apple's 40-column, uppercase-only
\ display.
\
\CONTENTS:
\ NEXT CROUT CROUTX TXT NUMOUT NUMERIC HEX NUMIN ALPHANUM MOVENAME
\ VERIFY DOREBEGIN ERROR FILERR
\ PRDATE PRWEEKDAY PRSYSDATE PRNAME PRENTRY PRTDEV
\ VALDRV CHKFILE NAME FIND SORT DIRSORT MOVIT GETDIR PUTDIR
\ WRTDIR RDDIR CHKDIR LOOKUP FINDFL
\ CMDGET CMDSTART CMDWS CMDNEW CMDSYS CMDSIZE CMDDATE
\ SHOWDIR CMDDIR CMDBD CMDTITLE CMDZERO CMDDF CMDDO
\ CHKNAME ENTER CLEAR REMOVE COPY PACK CLOFIL
\ CMDSQ CMDMAKE CMDDELETE CMDSAVE
\ OPENOT OPENIN CMDOPEN CMDCLOSE
\ CMDLIST CMDRENAME CMDUNLOCK CMDSUB
\ FIXSAV LOOKER DOCMD RUN MAIN
code
ABS=0, RAN=1, REM=2, RESERVE=3, SWAP=4,
REBEGIN=6, CHIN=7, CHOUT=8, CRLF=9, INTOUT=11,
TEXT=12, OPENI=13, OPENO=14, CLOSE=15,
SPACE=18, RERUN=19, FWRITE=30, FREAD=31, FRUN=28,
FGET=33, FASAVE=34, FSAVE=35, BLIT=36; \%%%
\THE DIRECTORY:
addr FNAME, \THE NAME AND EXTENSION FOR EACH FILE
FSTAT, \THE STATUS FOR EACH FILE
STAB, \SORT TABLE, ORDER IN ASCENDING "FBLK"S
NUMVAL, \LAST ELEMENT OF "STAB" ARRAY (MAXSTB)
DIRCHG, \"$A5" INDICATES DIRECTORY NEEDS TO BE SORTED
PRDEV, \DEFAULT DEVICE NUMBER
DFNAME, \THE DEFAULT FILE NAME AND EXTENTION
TITLE, \TITLE OF THE VOLUME
UNUSED, \UNUSED SPACE
FLAGS; \I.E: PACK, BACKUP, CHECK, UNLOCKED, ABORT, EXTENDED DIR
\16-BIT ARRAYS IN THE DIRECTORY: %%%
addr FBLK, \THE FIRST BLOCK OF EACH FILE
LBLK, \THE LAST BLOCK
FEMBLK, \EMPTY BLOCKS FILE LIST (FIRST BLOCK)
LEMBLK, \ (LAST BLOCK) SORTED LARGEST SIZE FIRST
PMAXB, \MAXIMUM BLOCK NUMBER (= UNIT SIZE -1)
APEXID, \A 4-BYTE VALUE USED TO RECOGNIZE AN APEX DISK
VOLUME, \UNIQUE VOLUME (DIRECTORY) ID NUMBER
DIRDAT, \DIRECTORY DATE (SYSTEM DATE)
FDATE; \DATE FOR EACH FILE
\SOME ABSOLUTE ADDRESS:
addr SYSPAG, \SYSTEM PAGE BASE ADDRESS
CMDBUF; \.CMD FILE BUFFER
\THE SYSTEM GLOBALS:
addr LOCNAM, \LOCAL NAME OF FILE (FROM TYPED IN COMMAND)
MOSTR, \ARRAY OF MONTH NAMES (STRING)
RNAM; \SYSTEM-WIDE DEFAULT FILE NAME AND EXTENSION
int ABOFLG, \FLAG: ABORT COMMAND FILES UPON ERRORS
ACTDEV, \DEVICE (UNIT) NUMBER OF ACTIVE DEVICE
ARG1, \COMMAND ARGUMENT
ARG2, \COMMAND ARGUMENT
BACKBLK, \BLOCK TO PUT BACKUP DIR IN
BAKFLG, \FLAG: BACKUPS WANTED
BITS, \ARRAY: BIT TABLE
BLKSIZ, \SIZE OF A BLOCK IN BYTES
CHAR, \LAST CHARACTER TYPED IN
CHKFLG, \FLAG: CHECKS WANTED
CONHT, \HEIGHT OF CONSOLE (LINES)
CONWID, \WIDTH OF CONSOLE (CHARACTERS)
DIRBLK, \BLOCK WHERE DIRECTORY STARTS
DIRDEV, \DEVICE WE HAVE THE DIRECTORY OF IN MEMORY
DIRSIZ, \DIRECTORY SIZE IN BLOCKS
DRVSET, \FLAG: DRIVE (UNIT) SPECIFIED
FIRBLK, \FIRST BLOCK OF FILE
FLNO, \NUMBER OF FILE
GOTFILE, \FLAG: 'PROC' NAME GOT A FILE NAME (NOT JUST A SPACE)
INDATE, \DATE OF LAST INFILE
INSIZE, \SIZE OF LAST OPENED INFILE (BLOCKS)
LASBLK, \LAST BLOCK OF FILE
LINECTR, \LINE COUNTER (TO PAUSE ON SCREEN BOUNDARIES)
LOCDEV, \DEVICE (UNIT) USER ASKED FOR IN TYPED IN COMMAND
MAXBLK, \MAXIMUM BLOCK NUMBER ALLOWED ON UNIT
MAXFL, \HIGHEST FILE NO.
MAXSTB, \LAST ELEMENT OF "STAB" ARRAY (NUMVAL)
PAKFLG, \FLAG: PACKING WANTED
RDEV, \DEFAULT UNIT NUMBER
SPECIAL, \BIT ARRAY: BACK UP, SIZE LIMIT, KEEP DATE
SWAPFLG, \FLAG: SWAPPING AREA IS VALID
SWITCH, \COMMAND SWITCH--I.E. CHAR FOLLOWING "/"
SYSDAT, \SYSTEM DATE
SYSDEV, \THE CURRENT SYSTEM DEVICE
USERBLK; \FIRST USER BLOCK (AFTER DIR AND RESCOD.SYS)
\32-BIT INTEGERS IN SYSTEM PAGE
int INLBLK, \LOW BLOCK NUMBER
INHBLK, \HIGH BLOCK NUMBER
OTLBLK, \FIRST BLOCK OF OUTPUT FILE (LOW BYTE)
OTHBLK, \LAST BLOCK OF OUTPUT FILE
SYSBLK, \BLOCK SYSTEM FILE IS IN
SWPBLK, \BLOCK SWAP FILE IS IN
USRMEM, \USER BASE ADDRESS
PROSIZ, \USER PROGRAM SIZE IN PAGES (NOT INCL SYSPAG)
MAXTBL, \BLOCK HANDLER LIMIT TABLE (MAX BLOCK + 1 OF SUB-DIRS)
OFFTBL, \BLOCK HANDLER OFFSET TABLE (BASE BLOCKS OF SUB-DIRS)
CMDPTR, \POINTER INTO COMMAND FILE BUFFER (COMBUF)
;
int DIRLEN; \ARRAY: LENGTHS (IN WORDS) OF SEGMENTS OF THE DIRECTORY
def MAXSEG=10; \THE LAST SEGMENT (ELEMENT) IN "DIRLEN"
def EXTPAT=$A5; \FLAG PATTERN INDICATING EXTENDED DIR IS USED
\FOR MAIN:
int HASH, \COMMAND CODE
II, \SCRATCH
COLD, \FLAG: COLD START
FILENO; \RUN FILE NUMBER
\ASCII CONSTANTS:
def BEL=$07, TAB=$09, LF=$0A, FF=$0C, CR=$0D, EOF=$1A, SP=$20;
\FILE STATUS IN THE DIRECTORY (FSTAT):
def NULL=0, TENTATIVE=255, REPLACE=254, VALID=1;
\FILE STATUS IN SYSTEM PAGE (INFLG, OTFLG):
def NOFILE=0, SETUP=1, CLOSED=255;
\SYSTEM REENTRY CONDITIONS (SYSENF):
def SWAPIN=254, SAVEIN=255, BOOTIN=253, RELOAD=252;
\FAILED FLAG
def NONE=$FFFF;
\DEFINE SOME OFFSETS INTO THE SYSTEM PAGE: %%%
\(SEE MAIN FOR ADDITIONAL DEFINITIONS)
def DEXTO=$5B, \DEFAULT EXT FOR OUTPUT FILE
DEXTI=$61, \DEFAULT EXT FOR INPUT FILE
DEFAUL=$67, \SPECIAL DEFAULT FLAG BYTE
SYSENF=$100, \FLAG SHOWING REENTRY CONDITION
SYSUNT=$101, \UNIT SYSTEM IS ON
DATOFF=$10A, \SYSTEM DATE (SYSDAT)
DATOF1=$10B,
DATOF2=$10C,
LOKMSK=$113, \BIT ARRAY OF WRITE-LOCKED UNITS
\++UNTUPD=$114,\ \BIT ARRAY SHOWING UNITS NEEDING ATTENTION
DEFUNT=$115, \USER'S DEFAULT UNIT
\OUTPUT FILE INFORMATION:
OTFLG=$15E, \OUTPUT FILE STATUS FLAGS (1=SETUP)
OTNO=$15F, \OUTPUT FILE NUMBER IN DIRECTORY
OTUNT=$160, \UNIT NUMBER OUTPUT FILE IS ON
\INPUT FILE INFORMATION:
INFLG=$16A, \INPUT FILE STATUS FLAG
INNO=$16B, \INPUT FILE NUMBER IN DIRECTORY
INUNT=$16C, \DEVICE NUMBER INPUT FILE IS ON
CMDMODE=$28A, \FLAG: COMMAND MODE (.CMD FILE)
;
\----------------------------------------------------------------------\
proc PUT16(ARRAY, INDEX, VALUE);
\STORE A 16-BIT VALUE INTO THE DIRECTORY ARRAY ENTRY AT "INDEX"
\NOTE THE BYTE ORDER IS LOW BYTE, HIGH BYTE
addr ARRAY;
int INDEX, VALUE;
begin
INDEX:= INDEX + INDEX; \DOUBLE FOR WORD ENTRIES
ARRAY(INDEX):= VALUE; \STORE LOW BYTE
ARRAY(INDEX+1):= SWAP(VALUE); \STORE HIGH BYTE
end; \PUT16
func GET16(ARRAY, INDEX);
\RETURN A 16-BIT VALUE FROM THE DIRECTORY ARRAY ENTRY AT "INDEX"
\NOTE THE BYTE ORDER IS LOW BYTE, HIGH BYTE
addr ARRAY;
int INDEX;
begin
INDEX:= INDEX + INDEX; \DOUBLE FOR WORD ENTRIES
return ARRAY(INDEX) + SWAP(ARRAY(INDEX+1));
end; \GET16
proc NEXT; \GET NEXT CHARACTER, SET SWITCH IF ANY
func GETCH;
\RETURN "CHAR" FROM KEYBOARD, CONVERT TO UPPERCASE
begin
CHAR:= CHIN(0);
if CHAR>=^a & CHAR<=^z then CHAR:= CHAR-32;
end; \GETCH
begin
GETCH;
if CHAR=^/ then
begin
GETCH;
SWITCH:= CHAR;
GETCH;
end;
end; \NEXT
proc CROUT; \DO A CRLF
CRLF(0);
proc CROUTX; \CROUT, BUT PAUSE ON SCREEN BOUNDARIES
int I;
begin
if LINECTR>=CONHT then [I:= CHIN(1); LINECTR:= 0];
CROUT;
LINECTR:= LINECTR + 1;
end; \CROUTX
proc TXT(STR); \OUTPUT A STRING
addr STR;
TEXT(0,STR);
proc NUMOUT(I); \OUTPUT AN INTEGER
int I;
INTOUT(0,I);
func NUMERIC; \RETURNS 'TRUE' IF LAST CHARACTER READ WAS A DIGIT
return CHAR>=^0 & CHAR<=^9;
func HEX; \RETURNS 'TRUE' IF LAST CHARACTER WAS A HEX DIGIT
return NUMERIC ! (CHAR>=^A & CHAR<=^F);
func NUMIN; \GET AN UNSIGNED DECIMAL OR HEX INTEGER
int I,ADD;
begin
while (not NUMERIC) & (CHAR#^$) do NEXT;
I:= 0;
if CHAR=^$ then
begin \HEX
NEXT;
while HEX do
begin
if CHAR<^A then ADD:= CHAR -^0
else ADD:= CHAR -^A +10;
I:= I*16 +ADD;
NEXT;
end;
end
else while NUMERIC do [I:= I *10 +CHAR -^0; NEXT]; \DECIMAL
return I;
end; \NUMIN
func ALPHANUM; \RETURNS 'TRUE' IF LAST CHAR WAS ALPHANUMERIC OR "?"
return NUMERIC ! (CHAR>=^A & CHAR<=^Z) ! CHAR=^?;
proc MOVENAME(A,B); \MOVE A FILE NAME FROM A TO B
addr A, B;
int I;
for I:= 0,10 do B(I):= A(I);
\----------------------------------------------------------------------\
func VERIFY;
begin
TXT(" - ARE YOU SURE (N/Y)? ");
OPENI(0);
NEXT;
return CHAR = ^Y;
end; \VERIFY
proc DOREBEGIN; \RESTART APEX ON ERRORS
begin
if ABOFLG then \ABORT COMMAND FILE (IF ANY)
SYSPAG(CMDMODE):= false;
SYSPAG(SYSENF):= BOOTIN;
REBEGIN;
end; \DOREBEGIN
proc ERROR(LINE); \ERROR HANDLER
addr LINE;
begin
CHOUT(0,BEL);
TXT(if RAN(10)<3 then "OOPS - " else "NOPE - ");
TXT(LINE);
DOREBEGIN;
end; \ERROR
proc FILERR; \FILE-NOT-FOUND ERROR HANDLER
int I;
addr LINE;
begin
CHOUT(0,BEL);
TXT("I CAN'T FIND ");
NUMOUT(LOCDEV); CHOUT(0,^:);
for I:= 0,7 do
if LOCNAM(I)#SP
then CHOUT(0,LOCNAM(I));
if LOCNAM(8)#SP then
begin
CHOUT(0,^.);
for I:= 8,10 do
CHOUT(0,LOCNAM(I));
end;
DOREBEGIN;
end; \FILERR
proc FORMERR;
ERROR("NO FILES OF THAT FORM");
\----------------------------------------------------------------------\
proc PRDATE(DATE); \OUTPUT THE DATE, E.G: NOV-07-85
int DATE;
int DAY,MO,I;
proc NUM2(N);
int N;
begin
if N<10 then CHOUT(0,^0);
NUMOUT(N);
end; \NUM2
begin
if DATE<=0 then [TXT("NO DATE "); return];
DATE:= DATE/32;
DAY:= REM(0);
DATE:= DATE/16;
MO:= REM(0);
MO:= (MO-1)*3;
for I:= 0,2 do CHOUT(0,MOSTR(MO+I));
CHOUT(0,^-);
NUM2(DAY);
CHOUT(0,^-);
NUM2(DATE+76);
end; \PRDATE
proc PRWEEKDAY(DATE); \PRINT THE DAY OF THE WEEK
int DATE;
int DAY,MO,YR,X,I;
addr DAYWRD;
begin
DAYWRD:= "MONTUEWEDTHUFRISATSUN";
if DATE<=0 then return;
YR:= DATE/32;
DAY:= REM(0);
YR:= YR/16;
MO:= REM(0);
if MO<=2 then [MO:= MO+10; YR:= YR-1] else MO:= MO-2;
X:= 3 *( REM(((26*MO - 2)/10 + DAY + YR + YR/4 + 60) /7) );
for I:= 0,2 do CHOUT(0,DAYWRD(X+I));
end; \PRWEEKDAY
proc PRSYSDATE; \PRINT THE SYSTEM DATE, E.G: THU, NOV-07-85
begin
PRWEEKDAY(SYSDAT);
TXT(", ");
PRDATE(SYSDAT);
end; \PRSYSDATE
proc PRNAME(FILE); \OUTPUT A FILE NAME
addr FILE;
int K;
begin
for K:= 0,7 do CHOUT(0,FILE(K));
CHOUT(0,^.);
for K:= 8,10 do CHOUT(0,FILE(K));
end; \PRNAME
proc PRENTRY(FILE,FLAG); \PRINT FILE ENTRY, E.G:
int FILE,FLAG; \FLAG: FILENAME.EXT 123 NOV-08-85 200-222
int MIN, MAX, SIZE; \ELSE: FILENAME.EXT 123
begin
PRNAME(FNAME +FILE*11);
MIN:= GET16(FBLK,FILE);
MAX:= GET16(LBLK,FILE);
SIZE:= MAX-MIN+1;
TXT(" "); NUMOUT(SIZE);
if not FLAG then return;
while SIZE<10000 do
begin
CHOUT(0,SP);
if SIZE>1000 then SIZE:= 10000 \(LIMIT PROBLEM)
else SIZE:= SIZE*10;
end;
CHOUT(0,SP);
if GET16(FDATE,FILE) = SYSDAT then TXT("TODAY ")
else PRDATE(GET16(FDATE,FILE));
TXT(" ");
NUMOUT(MIN); CHOUT(0,^-); NUMOUT(MAX);
end; \PRENTRY
proc PRTDEV(FILE); \PRINT UNIT AND FILE ENTRY
int FILE;
begin
NUMOUT(DIRDEV);
CHOUT(0,^:);
PRENTRY(FILE,CONWID>60); \SHOW LONG FORM IF CONSOLE IS WIDE ENOUGH
end; \PRTDEV
\----------------------------------------------------------------------\
proc VALDRV(DRV); \CHECK FOR VALID UNIT NUMBER
int DRV;
int I;
begin
if DRV<0 ! DRV>7 then ERROR("BAD UNIT NUMBER");
end; \VALDRV
proc CHKFILE;
begin
if CHAR#SP then ERROR("NEED FILE NAME");
end; \CHKFILE
proc NAME(DEFAULT,DDEV);
\GET A FILE NAME FROM THE OPERATOR AND PUT IT INTO "LOCNAM".
\ SET TO DEFAULT EXTENSION IF NONE WAS GIVEN. SET TO SYSTEM DEFAULT NAME (RNAM)
\ IF NONE WAS GIVEN. EXPAND *'S INTO FIELDS OF ?'S.
\OUTPUTS: LOCNAM FILE NAME AND EXTENSION
\ LOCDEV DEVICE (UNIT) NUMBER
\ GOTFILE FLAG: A FILE WAS INPUT (NOT JUST A SPACE)
\ DRVSET FLAG: A DEVICE NUMBER WAS EXPLICITLY SPECIFIED
\ ARG1, ARG2 GENERAL PURPOSE NUMERIC ARGUMENTS
\INPUTS: RNAM SYSTEM-WIDE DEFAULT FILE NAME AND EXTENSION
\NOTE: THE LOADER (LOAD.XPL) DEPENDS ON THIS ROUTINE HAVING A ONE-CHARACTER
\ LOOK AHEAD.
\
addr DEFAULT; \DEFAULT EXTENSION
int DDEV; \DEFAULT DEVICE NUMBER
int K;
begin
GOTFILE:= false;
while CHAR=SP do NEXT;
if NUMERIC then
[LOCDEV:= NUMIN; DRVSET:= true]
else [LOCDEV:= DDEV; DRVSET:= false];
VALDRV(LOCDEV);
if CHAR=^: then [NEXT; GOTFILE:= true];
K:= 0;
while ALPHANUM do
begin
LOCNAM(K):= CHAR;
if K<8 then K:= K+1;
NEXT;
GOTFILE:= true;
end;
if CHAR=^* then \FILL OUT THE REST OF THE NAME WITH "?"
[GOTFILE:= true;
for K:= K,7 do LOCNAM(K):= ^?;
NEXT]
else for K:= K,7 do LOCNAM(K):= SP;
if CHAR=^. then
begin
GOTFILE:= true;
NEXT;
K:= 8;
while ALPHANUM do
begin
LOCNAM(K):= CHAR;
if K<11 then K:= K+1;
NEXT;
end;
if CHAR=^* then
[for K:= K,10 do LOCNAM(K):= ^?;
NEXT]
else for K:= K,10 do LOCNAM(K):= SP;
end
else begin
LOCNAM(8):= DEFAULT(0);
LOCNAM(9):= DEFAULT(1);
LOCNAM(10):= DEFAULT(2);
end;
if LOCNAM(0)=SP then
for K:= 0,7 do LOCNAM(K):= RNAM(K);
if CHAR=^= then
begin
ARG1:= NUMIN;
if CHAR=^, then ARG2:= NUMIN
else ARG2:= NONE;
end
else [ARG1:= NONE; ARG2:= NONE];
end; \NAME
func FIND(BSIZ);
\FIND THE SMALLEST EMPTY WHICH IS "BSIZ" OR MORE.
\IF THERE IS NONE, THEN FIND THE LARGEST AVAILABLE.
\SET "FIRBLK" AND "LASBLK" TO IT. RETURN ITS SIZE.
\INPUTS: FEMBLK EMPTY BLOCKS ARRAY (FIRST BLOCK)
\ LEMBLK (LAST BLOCK)
int BSIZ; \THE BLOCK SIZE WE'RE LOOKING FOR
int LMAX, \SIZE OF MAX EMPTY
FMAX, \FILE NUMBER OF MAX EMPTY
I,SIZE;
begin
I:= 5;
LMAX:= 0; FMAX:= 0;
loop begin \SCAN LIST OF EMPTY BLOCKS FROM SMALLEST TO BIGGEST
SIZE:= if GET16(FEMBLK,I)=0 then 0
else GET16(LEMBLK,I) - GET16(FEMBLK,I) + 1;
if SIZE>LMAX then [LMAX:= SIZE; FMAX:= I];
if SIZE>=BSIZ then quit;
if I=0 then quit;
I:= I-1;
end;
if LMAX=0 then
begin
FIRBLK:= 0;
LASBLK:= 0;
return 0;
end;
if SIZE<BSIZ then I:= FMAX;
LASBLK:= GET16(LEMBLK,I);
FIRBLK:= GET16(FEMBLK,I);
return LASBLK-FIRBLK+1;
end; \FIND
\----------------------------------------------------------------------\
proc SORT(VAL,PTR,MAX);
\QUICKSORT POINTER ARRAY, "PTR", (0-"MAX"). "VAL" IS THE CORRESPONDENT
\ 16-BIT ARRAY OF INTEGER VALUES.
addr VAL; \%%%
addr PTR;
int MAX;
int N,KEY,L,R,T;
begin
N:= ((MAX+2)/2)-1;
KEY:= GET16(VAL,PTR(N));
L:= 0; R:= MAX;
loop begin
while GET16(VAL,PTR(L)) < KEY do L:= L+1;
while (GET16(VAL,PTR(R)) >= KEY) & (R>0) do R:= R-1;
if L>=R then quit;
T:= PTR(L);
PTR(L):= PTR(R);
PTR(R):= T;
end;
if GET16(VAL,PTR(R))>KEY then
begin
T:= PTR(R);
PTR(R):= PTR(N);
PTR(N):= T;
end;
if R>0 then SORT(VAL,PTR,R);
if MAX-R-1>0 then SORT(VAL,PTR+R+1,MAX-R-1);
end; \SORT
proc DIRSORT; \SORT DIRECTORY BY "FBLK" AND EMPTY SIZE
\INPUTS: MAXFL MAXIMUM POSSIBLE FILE NUMBER
\ STAB SORT TABLE (IN DIRECTORY)
\ FBLK FIRST BLOCK (IN DIRECTORY)
int I,J,K,
FEMB,LEMB, \FIRST & LAST EMPTY BLOCKS
MAXEM, \MAX
ESIZ; \EMPTY SIZE
addr FSTB,
FRESIZ; \ARRAY: FREE SIZE %%%
begin
\SORT THE FILES INTO ASCENDING "FIRST BLOCK NUMBERS" (FBLK)
J:= 0;
for I:= 0,MAXFL do
if FSTAT(I)=VALID then
[STAB(J):= I; J:= J+1];
MAXSTB:= J-1;
NUMVAL(0):= MAXSTB;
SORT(FBLK,STAB,MAXSTB);
\PRODUCE THE EMPTIES LIST
MAXEM:= MAXSTB+1;
FSTB:= RESERVE(MAXEM+1);
FRESIZ:= RESERVE(2*(MAXEM+1));
J:= 0;
for I:= 0,MAXEM do
begin
FEMB:= if I=0 then USERBLK
else GET16(LBLK,STAB(I-1)) +1;
LEMB:= if I=MAXEM then MAXBLK
else GET16(FBLK,STAB(I)) -1;
ESIZ:= LEMB-FEMB+1;
if ESIZ>0 then
begin
FSTB(J):= I;
PUT16(FRESIZ,I,ESIZ);
J:= J+1;
end;
end;
MAXEM:= J-1;
\SORT THE EMPTIES LIST BY SIZE
if MAXEM>=0 then
SORT(FRESIZ,FSTB,MAXEM);
\COPY THE EMPTIES LIST INTO THE DIRECTORY, BIGGEST FIRST
I:= MAXEM;
K:= 0;
while (K<6) & (I>=0) do
begin
J:= FSTB(I);
PUT16(FEMBLK, K, if J=0 then USERBLK
else GET16(LBLK,STAB(J-1)) +1);
PUT16(LEMBLK, K, if J>MAXSTB then MAXBLK
else GET16(FBLK,STAB(J)) -1);
K:= K+1;
I:= I-1;
end;
for I:= K,5 do [PUT16(FEMBLK,I,0); PUT16(LEMBLK,I,0)];
\FOR TESTS WE PRINT IT
\TEXT(0,"DIAG, EMPTIES LIST:"); CROUT;
\for I:= 0,5 do
\ begin
\ INTOUT(0,GET16(FEMBLK,I)); CHOUT(0,^,); INTOUT(0,GET16(LEMBLK,I));
\ CROUT;
\ end;
DIRCHG(0):= 0; \DIRECTORY IS NOW SORTED
end; \DIRSORT
\----------------------------------------------------------------------\
\
\DISK MAP:
\ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
\ BOOT +-- XD --+ +-- XB --+ +-- DI --+ +-- BD --+ +-- RESCOD -->
\ +------ EXTENDED -----+ +------ PRIMARY ------+
proc MOVIT(AB1,AB2,LEN); \MOVE "LEN" WORDS INTO B1 FROM B2
int AB1,AB2,LEN,LEN2; \B1 & B2 ARE LEFT POINTING TO THE LAST POSITION
int B1, B2, I;
begin
B1:= AB1(0);
B2:= AB2(0);
LEN2:= LEN+LEN;
BLIT(B2, B1, LEN2);
AB1(0):= B1 + LEN2;
AB2(0):= B2 + LEN2;
end; \MOVIT
proc GETDIR(DEV, BAKDIR); \READ IN THE DIRECTORY
int DEV, BAKDIR;
int I, EXTDIR, BASE1, BASE2, BASE3;
begin
EXTDIR:= RESERVE(1024);
\READ THE EXTENDED DIR INTO "EXTDIR"
FREAD(DEV, if BAKDIR then 5 else 1, EXTDIR, DIRSIZ);
\READ PRIMARY DIRECTORY INTO THE BIG DIRECTORY SPACE
FREAD(DEV, if BAKDIR then 13 else 9, FNAME, DIRSIZ);
\MERGE THE EXTENDED DIRECTORY INTO THE PRIMARY DIRECTORY
BASE1:= FNAME+528; \(FSTAT)
BASE2:= EXTDIR+528;
BASE3:= FSTAT;
for I:= 0,MAXSEG do
begin
MOVIT(addr BASE3, addr BASE1, DIRLEN(I));
MOVIT(addr BASE3, addr BASE2, DIRLEN(I));
end;
BLIT(EXTDIR, FNAME+528, 528);
MAXFL:= if FLAGS(7)=EXTPAT then 95 else 47;
end; \GETDIR
proc PUTDIR(DEV, BAKDIR); \WRITE THE DIRECTORY
int DEV, BAKDIR;
int I, EXTDIR, BASE1, BASE2, BASE3;
begin
EXTDIR:= RESERVE(1024);
\SEPARATE THE BIG DIR INTO THE PRIMARY DIR AND THE EXTENDED DIR
BLIT(FNAME+528, EXTDIR, 528);
BASE1:= FNAME+528;
BASE2:= EXTDIR+528;
BASE3:= FSTAT;
for I:= 0,MAXSEG do
begin
MOVIT(addr BASE1, addr BASE3, DIRLEN(I));
MOVIT(addr BASE2, addr BASE3, DIRLEN(I));
end;
\IF EXTENDED DIR IS USED THEN WRITE "EXTDIR" INTO THE EXTENDED DIR
if FLAGS(7)=EXTPAT then
FWRITE(DEV, if BAKDIR then 5 else 1, EXTDIR, DIRSIZ);
\WRITE THE PRIMARY DIR
FWRITE(DEV, if BAKDIR then 13 else 9, FNAME, DIRSIZ);
\NOW FIX THE BIG DIR
BLIT(EXTDIR, FNAME+528, 528);
end; \PUTDIR
\----------------------------------------------------------------------\
proc LOCKERR;
begin
if FLAGS(3) then else ERROR("UNIT IS WRITE LOCKED");
end; \LOCKERR
proc WRTDIR; \WRITE THE DIRECTORY; MAKE SURE IT'S SORTED
addr BLOCK;
def VOLOFF=74; \OFFSET INTO 3RD BLOCK FOR VOLUME NUMBER (IN WORDS)
begin
BLOCK:= RESERVE(BLKSIZ);
FREAD(DIRDEV,DIRBLK+3,BLOCK,1);
if GET16(BLOCK,VOLOFF) # GET16(VOLUME,0) then
ERROR("YOU CHANGED DISKS!"); \YOU IDIOT!
LOCKERR;
DIRSORT;
\++SYSPAG(UNTUPD):= SYSPAG(UNTUPD) & (not BITS(DIRDEV));
APEXID(0):= ^a;
APEXID(1):= ^p;
APEXID(2):= ^e;
APEXID(3):= ^x;
PUTDIR(DIRDEV,false);
end; \WRTDIR
proc RDDIR(DEV); \READ DIRECTORY FROM DEVICE "DEV"
int DEV;
begin
VALDRV(DEV);
DIRDEV:= DEV;
GETDIR(DIRDEV,false);
MAXBLK:= GET16(PMAXB,0);
MAXSTB:= NUMVAL(0);
if MAXSTB>MAXFL then MAXSTB:= -1; \IN CASE IT'S EMPTY
\SET THE SYSTEM PAGE DEVICE SIZE TABLE
MAXTBL(DEV):= OFFTBL(DEV) + MAXBLK + 1;
\SET THE WRITE LOCK BIT IF THE FLAGS SAY SO (FLAG: TRUE = WRITE ENABLE = 1 BIT)
if FLAGS(3) then SYSPAG(LOKMSK):= SYSPAG(LOKMSK) ! BITS(DEV)
else SYSPAG(LOKMSK):= SYSPAG(LOKMSK) & (not BITS(DEV));
if DIRCHG(0)=$A5 & APEXID(0)=^a & APEXID(1)=^p & APEXID(2)=^e & APEXID(3)=^x then
\IT'S VERY LIKELY AN APEX DISK WHICH NEEDS SORTING.
\If an external program changed the directory then we fix it here.
\ In this version, we do not fix units unless we read the directory for
\ Apex purposes. That is, we don't fix them until we use them.
\ This affects programs which use FILEX, e.g. BASIC, in that if we go
\ directly from something that affects the directory, say COPY.SAV,
\ into BASIC without reading the directory with Apex then we will
\ give FILEX an incorrect STAB array. FILEX should detect this error,
\(not done yet)
\+++ ! ((SYSPAG(UNTUPD) & BITS(DEV)) # 0)
\If we can, we sort and re-write, if not we just sort:
if FLAGS(3) then WRTDIR else DIRSORT;
end; \RDDIR
proc CHKDIR(DEV); \MAKE SURE THE DIRECTORY IS IN MEMORY
int DEV;
begin
if DIRDEV#DEV then RDDIR(DEV);
end; \CHKDIR
func LOOKUP(FILE);
\LOOKUP THE FILENAME IN "LOCNAM" BEGINNING AT DIRECTORY ENTRY NUMBER "FILE".
\TAKE "?" AS WILD CHARACTERS.
int FILE;
int FILE11, L;
begin
CHKDIR(LOCDEV);
loop begin
if FSTAT(FILE)=VALID then
begin
FILE11:= FILE*11;
L:= 0;
loop begin
if (LOCNAM(L) # ^?) & (FNAME(FILE11+L) # LOCNAM(L))
then quit;
L:= L+1;
if L>=11 then return FILE;
end;
end;
FILE:= FILE+1;
if FILE>MAXFL then return NONE;
end;
end; \LOOKUP
func FINDFL(DEV,FILNAM); \RETURN THE FILE NUMBER OF "FILNAM"
int DEV;
addr FILNAM;
int I;
begin
LOCDEV:= DEV;
for I:= 0,9 do LOCNAM(I):= FILNAM(I);
LOCNAM(10):= FILNAM(10);
return LOOKUP(0);
end; \FINDFL
\----------------------------------------------------------------------\
proc CMDGET; \COMMAND: GET
int FILENO;
begin
CHKFILE;
NAME("SAV",ACTDEV);
FILENO:= LOOKUP(0);
if FILENO=NONE then FILERR;
TXT(" INFILE: "); PRTDEV(FILENO); CROUT;
FGET(LOCDEV,GET16(FBLK,FILENO)); \(NEVER RETURNS)
end; \CMDGET
proc CMDSTART(FLAG); \COMMANDS: START & SWAP
int FLAG;
begin
if not SWAPFLG then
begin
TXT("I WILL SWAP TO UNKNOWN STATE");
if not VERIFY then return;
end;
if FLAG then FRUN(SYSDEV,SWPBLK(0)) else FGET(SYSDEV,SWPBLK(0));
end; \CMDSTART
\proc CMDWS; \\COMMAND: WS
\int I,FILE; \\WRITE SYSTEM
\begin
\while CHAR=SP do NEXT;
\if NUMERIC then ACTDEV:= NUMIN;
\TXT("RE-WRITE SYSTEM ON UNIT "); NUMOUT(ACTDEV);
\if not VERIFY then return;
\LOCKERR;
\FILE:= FINDFL(ACTDEV,"SYSTEM SYS");
\if FILE=NONE then ERROR("NOT A SYSTEM UNIT");
\FASAVE(LOCDEV,GET16(FBLK,FILE));
\end; \\CMDWS
proc CMDNEW(DEV); \COMMAND: NEW
int DEV; \NEW SYSTEM UNIT
begin
VALDRV(DEV);
SYSDEV:= DEV;
RDDIR(DEV);
RDEV:= PRDEV(0);
SYSPAG(DEFUNT):= RDEV;
MOVENAME(DFNAME, RNAM);
PAKFLG:= FLAGS(0)#0;
BAKFLG:= FLAGS(1)#0;
CHKFLG:= FLAGS(2)#0;
ABOFLG:= FLAGS(5)#0;
if SYSPAG(DATOF2) # ( $FF & (not (SYSPAG(DATOFF)&SYSPAG(DATOF1))) ) then
begin \WE DON'T HAVE A VALID SYSTEM DATE IN MEMORY
TXT("DATE FROM SYSTEM UNIT: "); \GET IT FROM THE DISKETTE
SYSDAT:= GET16(DIRDAT,0);
SYSPAG(DATOFF):= SYSDAT;
SYSPAG(DATOF1):= SWAP(SYSDAT);
SYSPAG(DATOF2):= not (SYSPAG(DATOFF)&SYSPAG(DATOF1));
PRSYSDATE;
CROUT;
end
end; \CMDNEW
\STRIDE VERSION:
\proc CMDSYS; \\COMMAND: SYSTEM
\int UNIT;
\addr MEM; \\BASE ADDRESS OF RESCODE
\ext BOOT =$404; \\ENTRY POINT TO BOOT.68K
\begin
\MEM:= $0400;
\while CHAR=SP do NEXT;
\if NUMERIC then
\ begin
\ UNIT:= NUMIN;
\ FREAD(UNIT, 0, MEM, $80); \\READ IN RESCOD.SYS, ETC.
\ MEM($1500 +SYSUNT):= UNIT;
\ BOOT;
\ end
\else begin
\ TXT("SYSTEM DEVICE: "); NUMOUT(SYSDEV); CROUT;
\ end;
\end; \\CMDSYS
\AMIGA VERSION:
proc CMDSYS; \COMMAND: SYSTEM
int UNIT;
addr MEM; \BASE ADDRESS OF RESCODE
ext VSTART =$400; \ENTRY POINT TO RESTART APEX
begin
MEM:= $0400;
while CHAR=SP do NEXT;
if NUMERIC then
begin
UNIT:= NUMIN;
MEM(SYSUNT):= UNIT;
VSTART;
end
else begin
TXT("SYSTEM DEVICE: "); NUMOUT(SYSDEV); CROUT;
end;
end; \CMDSYS
proc CMDSIZE; \COMMAND: SIZE
\OUTPUTS: MAXBLK
\ PMAXB
begin
while CHAR=SP do NEXT;
if NUMERIC then ACTDEV:= NUMIN;
if CHAR=^: then NEXT;
CHKDIR(ACTDEV);
if CHAR=^= then
begin
TXT("NOW ");
MAXBLK:= NUMIN - 1;
PUT16(PMAXB, 0, MAXBLK);
WRTDIR;
RDDIR(ACTDEV); \to change the protections! ????
end;
TXT("UNIT "); NUMOUT(ACTDEV); TXT(" HAS SIZE "); NUMOUT(MAXBLK+1); CROUT;
end; \CMDSIZE
\----------------------------------------------------------------------\
proc CMDDATE; \COMMAND: DATE
int COUNT, FILENO, NEWDATE;
func GETDATE(DFDATE); \GET A DATE FROM THE OPERATOR
int DFDATE; \DEFAULT DATE
int I, MO, DAY, YR;
addr STR;
func GETMO(STR); \RETURN THE NUMBER OF THE MONTH
addr STR; \STRING CONTAINING THE SPELLED-OUT MONTH NAME
int I,J,K,MO;
begin
J:= 0;
for MO:= 1,12 do
begin
K:= 0;
for I:= 0,2 do
begin
if STR(I)=MOSTR(J) then K:= K+1;
J:= J+1;
end;
if K=3 then return MO;
end;
return 0; \RETURN "0" IF MONTH NOT FOUND
end; \GETMO
begin \GETDATE
DFDATE:= DFDATE/32;
DAY:= REM(0);
YR:= DFDATE/16 +76;
MO:= REM(0);
NEXT;
loop begin
while not ALPHANUM do [if CHAR=CR then quit; NEXT];
if NUMERIC then I:= NUMIN
else begin
STR:= RESERVE(3);
for I:= 0,2 do [STR(I):= CHAR; if CHAR=CR then quit; NEXT];
I:= GETMO(STR);
end;
if I<1 ! I>12 then quit;
MO:= I;
while not NUMERIC do [if CHAR=CR then quit; NEXT];
I:= NUMIN;
if I<1 ! I>31 then quit;
DAY:= I;
while not NUMERIC do [if CHAR=CR then quit; NEXT];
YR:= REM(NUMIN/100);
quit;
end;
return ((YR - 76)*16 + MO)*32 + DAY;
end; \GETDATE
begin \CMDDATE
if CHAR=SP then
begin \A PARTICULAR FILE WAS SPECIFIED
NAME(RNAM+8,ACTDEV);
COUNT:= 0;
FILENO:= LOOKUP(0);
while FILENO#NONE do
begin
COUNT:= COUNT+1;
PUT16(FDATE, FILENO, SYSDAT);
TXT(" REDATE: "); PRTDEV(FILENO); CROUT;
FILENO:= LOOKUP(FILENO+1);
end;
if COUNT=0 then FORMERR;
if COUNT>=2 then
[if VERIFY then WRTDIR else DIRDEV:= $FF]
else WRTDIR;
end
else begin
CHKDIR(SYSDEV);
loop begin
TXT("NEW DATE (MM-DD-YY)? ");
OPENI(0);
NEWDATE:= GETDATE(SYSDAT);
if NEWDATE >= SYSDAT then quit;
if VERIFY then quit;
end;
SYSDAT:= NEWDATE;
PUT16(DIRDAT, 0, SYSDAT);
SYSPAG(DATOFF):= SYSDAT;
SYSPAG(DATOF1):= SWAP(SYSDAT);
SYSPAG(DATOF2):= not (SYSPAG(DATOFF) & SYSPAG(DATOF1));
TXT("TODAY IS "); PRSYSDATE; CROUT;
WRTDIR;
end;
end; \CMDDATE
\----------------------------------------------------------------------\
proc SHOWDIR; \SHOW A DIRECTORY (MAIN OR BACKUP)
\INPUTS: MAXSTB
addr ARRAY; \ARRAY FOR SORTING ASSORTED ITEMS %%%
int I,
SUM, \SUM OF FREE BLOCKS
FILENO,
FLAG, \FOUND A FILE OF SPECIFIED FORM
COLS; \COLUMNS OF FILE NAMES
func RADIX40(STR); \RETURNS A 16-BIT VALUE FOR A 3-CHAR STRING
addr STR; \LEGAL CHARS ARE: A-Z, 0-9, AND SPACE.
int I, C;
func CODE(CH); \RETURN A CHARACTER CODE
int CH;
begin
if CH>=^A \& CH<=^Z\ then return CH-$40; \(1-26)
if CH>=^0 \& CH<=^9\ then return CH-21; \(27-36)
return 0; \(FOR SPACE)
end; \CODE
begin
C:= 0;
for I:= 0,2 do
C:= C*40 + CODE(STR(I));
return C;
end; \RADIX40
begin
OPENI(1);
LINECTR:= 1;
COLS:= CONWID/20;
PRSYSDATE; TXT(" "); \%%%
TXT("VOL: "); NUMOUT(GET16(VOLUME,0));
TXT(" UNIT: "); NUMOUT(DIRDEV);
if FLAGS(3) then else TXT(" (LOCKED)"); CROUTX;
TITLE(63):= 0; \MAKE SURE GARBAGE TITLE IS TERMINATED
TXT(TITLE); CROUTX;
if GOTFILE then
begin \A PARTICULAR FILE WAS SPECIFIED (NOT JUST
FLAG:= true; \ A SPACE)
FILENO:= LOOKUP(0);
while FILENO#NONE do
begin
FLAG:= false;
PRENTRY(FILENO,true); CROUTX;
FILENO:= LOOKUP(FILENO+1);
end;
if FLAG then FORMERR;
end
else begin
if SWITCH#SP then
begin
ARRAY:= RESERVE((MAXFL+1)*2);
case SWITCH of
^N: for I:= 0,MAXFL do \NAME
PUT16(ARRAY, I, RADIX40(FNAME + I*11));
^E: for I:= 0,MAXFL do \EXT
PUT16(ARRAY, I, RADIX40(FNAME + I*11 + 8));
^S: for I:= 0,MAXFL do \SIZE
PUT16(ARRAY, I, GET16(LBLK,I)-GET16(FBLK,I));
^D: [ARRAY:= FDATE] \DATE
other ARRAY:= FBLK; \BLOCK
SORT(ARRAY,STAB,MAXSTB);
DIRDEV:= $FF; \(DON'T KEEP A STRANGE STAB)
end;
for I:= 0,MAXSTB do
begin \NO FILE SPECIFIED, SHOW THEM ALL
if SWITCH=SP then
begin \SHORT FORM
PRNAME(FNAME +STAB(I)*11);
if REM(I/COLS)=COLS-1 ! I=MAXSTB then CROUTX
else TXT(" ");
end
else begin \LONG FORM
PRENTRY(STAB(I),true); CROUTX;
end;
end;
end;
SUM:= MAXBLK - USERBLK + 1;
for I:= 0,MAXFL do
if FSTAT(I)=VALID then
begin
SUM:= SUM - (GET16(LBLK,I) - GET16(FBLK,I) + 1);
end;
if SUM<0 then SUM:= 0;
TXT("FILES: "); NUMOUT(MAXSTB+1);
TXT(" FREE: "); NUMOUT(SUM);
TXT(" MAX: "); NUMOUT(FIND(32767));
TXT(" SIZE: "); NUMOUT(MAXBLK+1); CROUTX; \%%%
CROUTX;
end; \SHOWDIR
proc CMDDIR; \COMMAND: DIRECTORY
begin
NAME(RNAM+8,ACTDEV);
CHKDIR(LOCDEV);
SHOWDIR;
end; \CMDDIR
proc CMDBD; \COMMAND BD
begin
NAME(RNAM+8,ACTDEV);
ACTDEV:= LOCDEV;
VALDRV(ACTDEV);
if SWITCH=^B then
begin
TXT("BACKING DIRECTORY ON UNIT "); NUMOUT(ACTDEV); CROUT;
GETDIR(ACTDEV,false);
PUTDIR(ACTDEV,true);
end
else begin
GETDIR(ACTDEV,true);
DIRDEV:= ACTDEV;
MAXBLK:= GET16(PMAXB,0);
if SWITCH=^W then
begin
TXT("ABOUT TO RE-WRITE DIRECTORY ON UNIT "); NUMOUT(ACTDEV);
if VERIFY then PUTDIR(ACTDEV,false);
end \(WRITE LOCK NOT CHECKED)
else begin
DIRSORT;
SHOWDIR;
end;
end;
DIRDEV:= $FF; \WE DO NOT HAVE A VALID DRIVE IN MEMORY
end; \CMDBD
\----------------------------------------------------------------------\
proc CMDTITLE; \COMMAND: TITLE
int I;
begin
while CHAR=SP do NEXT;
if NUMERIC then ACTDEV:= NUMIN;
CHKDIR(ACTDEV); \MAKE SURE WE HAVE A VALID DIRECTORY
while not ALPHANUM do NEXT;
while CHAR=^: ! CHAR=SP do NEXT;
I:= 0;
while CHAR#CR do
begin
TITLE(I):= CHAR;
if I<31 then I:= I+1;
NEXT;
end;
TITLE(I):= 0; \TERMINATE TITLE STRING
PUT16( VOLUME, 0, ABS(SYSDAT*256 + RAN(256)) );
LOCKERR;
PUTDIR(DIRDEV,false); \(DON'T WRTDIR BECAUSE WE DIDN'T CHANGE DISKS)
end; \CMDTITLE
proc CMDZERO; \COMMAND: ZERO
int I;
begin
while CHAR=SP do NEXT;
if NUMERIC then ACTDEV:= NUMIN;
CHKDIR(ACTDEV);
TXT("ABOUT TO ZERO UNIT "); NUMOUT(DIRDEV); CROUT;
TITLE(63):= 0; \MAKE SURE GARBAGE TITLE IS TERMINATED
TXT(TITLE); CROUT;
if not VERIFY then return;
for I:= 0,MAXFL do FSTAT(I):= NULL;
TITLE(0):= CR; TITLE(1):= 0;
FLAGS(7):= EXTPAT; \ENABLE EXTENDED DIRECTORY
WRTDIR;
end; \CMDZERO
proc CMDDF; \COMMAND: DF
addr BLOCK;
proc SHOW(STR,FLAG);
addr STR;
int FLAG;
begin
TXT(STR);
CHOUT(0,if FLAG then ^T else ^F);
end; \SHOW
begin \CMDDF
TXT("DEFAULT NAME: ");
if CHAR=SP then
begin
NAME(RNAM+8, RDEV);
BLOCK:= RESERVE(256);
FREAD(SYSDEV, DIRBLK+3, BLOCK, 1);
MOVENAME(LOCNAM, RNAM);
MOVENAME(LOCNAM, BLOCK+$4D);
RDEV:= LOCDEV;
SYSPAG(DEFUNT):= LOCDEV;
BLOCK($4A):= LOCDEV;
FWRITE(SYSDEV, DIRBLK+3, BLOCK, 1);
DIRDEV:= $FF; \FORCE READ OF ALTERED DIRECTORY
end;
NUMOUT(RDEV); TXT(":"); PRNAME(RNAM); CROUT;
SHOW("BACKUP: ", BAKFLG);
SHOW(" ABORT: ", ABOFLG);
CROUT;
SHOW("PACK: ", PAKFLG);
SHOW(" CHECK: ", CHKFLG);
CROUT;
CROUT;
end; \CMDDF
proc CMDDO(FL); \COMMANDS: DO & NO
int FL;
int HASH;
begin
while CHAR=SP do NEXT;
HASH:= CHAR;
if CHAR#CR then NEXT else ERROR("NEED FLAG");
HASH:= HASH + SWAP(CHAR);
CHKDIR(SYSDEV);
case HASH of
$4150\PA\: [FLAGS(0):= FL; PAKFLG:= FL];
$4142\BA\: [FLAGS(1):= FL; BAKFLG:= FL];
$4843\CH\: [FLAGS(2):= FL; CHKFLG:= FL];
$4241\AB\: [FLAGS(5):= FL; ABOFLG:= FL]
other ERROR("FLAG DOES NOT EXIST");
WRTDIR;
end; \CMDDO
\----------------------------------------------------------------------\
proc CHKNAME; \CHECK FOR VALID NAME IN "LOCNAM"
int K;
begin
if (LOCNAM(8)=^B) & (LOCNAM(9)=^A) & (LOCNAM(10)=^K) then
ERROR("YOU MAY NOT MAKE .BAK FILES");
for K:= 0,10 do
if LOCNAM(K)=^? then
ERROR("OUT FILE CANNOT HAVE ?'S OR *'S");
end; \CHKNAME
proc ENTER;
\ENTER A TENTATIVE OUTPUT FILE AND ITS BLOCKS INTO THE DIRECTORY.
\DON'T RESERVE THE BLOCKS, DON'T MARK IT VALID.
\IF "BACKUP" IS ENABLED, MARK IT "TENATIVE", OTHERWISE MARK IT "REPLACE".
\THE FILE WILL BE MARKED VALID AND BACKUPS WILL BE MAKE WHEN IT IS CLOSED.
begin
CHKNAME;
\FIND AN EMPTY DIR SLOT
FLNO:= 0;
while FSTAT(FLNO)=VALID do
begin
FLNO:= FLNO+1;
if FLNO>MAXFL then
ERROR("DIRECTORY IS FULL");
end;
\NOW COPY THE NAME INTO IT
MOVENAME(LOCNAM, FNAME +FLNO*11);
PUT16(FBLK,FLNO,FIRBLK);
PUT16(LBLK,FLNO,LASBLK);
FSTAT(FLNO):= if (SPECIAL&1)&BAKFLG then TENTATIVE else REPLACE;
PUT16(FDATE, FLNO, if SPECIAL&4 then INDATE else SYSDAT);
end; \ENTER
\----------------------------------------------------------------------\
proc CLEAR(FILE); \REMOVE AN ENTRY FROM THE DIRECTORY
int FILE,MIN,MAX,I;
begin
if FSTAT(FILE)#VALID then return;
FSTAT(FILE):= NULL;
TXT("REMOVING ");
PRTDEV(FILE);
CROUT;
end; \CLEAR
proc REMOVE; \REMOVE ANY COLLISIONS WITH "LOCNAM"
int FILENO;
begin
FILENO:= LOOKUP(0);
if FILENO#NONE then CLEAR(FILENO);
end; \REMOVE
proc COPY(FRBLK,TOBLK,SIZE); \(USED ONLY BY PACKING AND CHECKING)
int FRBLK,TOBLK,SIZE,BUFSIZ,XFER;
addr BUFFER;
begin \CHECK ONLY IF TOBLK<0
if TOBLK>0 & FRBLK<TOBLK then ERROR("COPY TROUBLE");
BUFSIZ:= $40;
\BUFFER:= RESERVE($100 *BUFSIZ);
BUFFER:= $3000; \WARNING! CLOBBERS USER SPACE ($3000 - $6FFF)
SWAPFLG:= false; \INDICATE INVALID USER MEMORY
while SIZE > 0 do
begin
XFER:= if SIZE>BUFSIZ then BUFSIZ else SIZE;
FREAD(LOCDEV,FRBLK,BUFFER,XFER);
FRBLK:= FRBLK+XFER;
if TOBLK >= 0 then
begin
FWRITE(LOCDEV,TOBLK,BUFFER,XFER);
TOBLK:= TOBLK + XFER;
end;
SIZE:= SIZE-XFER;
end;
end; \COPY
proc PACK(FILE);
int FILE,SIZE;
begin
if not PAKFLG then return; \RETURN IF PACK IS OFF
SIZE:= GET16(LBLK,FILE) - GET16(FBLK,FILE) + 1;
if FIND(SIZE) < SIZE then return;
if GET16(FBLK,FILE) <= FIRBLK then return;
\WE CAN PACK IT, SO...
TXT("PACKING: "); PRTDEV(FILE);
TXT(" TO: "); NUMOUT(FIRBLK); CROUT;
COPY(GET16(FBLK,FILE), FIRBLK, SIZE);
PUT16(FBLK, FILE, FIRBLK);
PUT16(LBLK, FILE, FIRBLK+SIZE-1);
end; \PACK
proc CLOFIL(FILE,PAF);
\CLOSE THE TENTATIVE FILE BY DIRECTORY NUMBER.
\ASSUME IT HAS BEEN ENTERED. REMOVE COLLISIONS.
int FILE,PAF;
int S;
begin
S:= FSTAT(FILE);
if S#TENTATIVE & S#REPLACE then
begin
TXT("
???
");
return;
end;
MOVENAME(FNAME +FILE*11, LOCNAM);
REMOVE;
FSTAT(FILE):= VALID;
TXT("CLOSING: ");
PRTDEV(FILE);
CROUT;
if PAF then PACK(FILE);
if CHKFLG then COPY(GET16(FBLK,FILE), -1, GET16(LBLK,FILE)-GET16(FBLK,FILE)+1);
end; \CLOFIL
\----------------------------------------------------------------------\
proc CMDSQ; \COMMAND: SQUASH
int UBL, FILENO;
\THIS IS INEFFECIENT BECAUSE OF THE (STUPID) DIRECTORY SORT IN WRTDIR
proc SQ(FILENO);
int FILENO;
int FBL, LBL, SIZ, FL;
begin
FL:= STAB(FILENO);
FBL:= GET16(FBLK, FL);
LBL:= GET16(LBLK, FL);
SIZ:= LBL - FBL + 1;
if UBL < FBL then
begin
TXT("MOVING: "); PRTDEV(FL);
TXT(" TO: "); NUMOUT(UBL);
CROUT;
COPY(FBL, UBL, SIZ);
PUT16(FBLK, FL, UBL);
PUT16(LBLK, FL, UBL+SIZ-1);
WRTDIR;
end;
UBL:= GET16(LBLK, FL) + 1;
end; \SQ
begin \CMDSQ
while CHAR=SP do NEXT; \GET THE UNIT NUMBER, IF SPECIFIED
if NUMERIC then ACTDEV:= NUMIN; \ AND READ IN THE DIRECTORY
CHKDIR(ACTDEV); \MAKE SURE WE HAVE A VALID DIRECTORY
LOCDEV:= ACTDEV; \(BECAUSE OF COPY)
UBL:= USERBLK;
for FILENO:= 0, MAXSTB do SQ(FILENO);
WRTDIR;
PUTDIR(ACTDEV,true); \ALSO UPDATE BACKUP DIRECTORY
end; \CMDSQ
\----------------------------------------------------------------------\
proc CMDMAKE; \COMMAND: MAKE
int K, FILENO, TEXT;
addr BLOCK;
begin
CHKFILE;
NAME(RNAM+8,ACTDEV);
FILENO:= LOOKUP(0);
if FILENO#NONE then
begin
TXT("I WILL MUNCH OLD ONE! ");
if not VERIFY then return else REMOVE;
end;
if ARG1=NONE then
begin
ARG1:= 1;
ARG2:= NONE;
TEXT:= true;
end
else TEXT:= false;
if ARG2=NONE then
begin
if FIND(ARG1) < ARG1 then
ERROR("NOT ENOUGH SPACE ON THAT UNIT");
LASBLK:= FIRBLK+ARG1-1;
end
else begin
FIRBLK:= ARG2;
LASBLK:= ARG2+ARG1-1;
end;
ENTER;
CLOFIL(FLNO,false); \(DON'T ALLOW PACKING)
WRTDIR;
if TEXT then
begin
BLOCK:= RESERVE(256);
BLOCK(0):= $1A;
FWRITE(LOCDEV,FIRBLK,BLOCK,1);
end;
end; \CMDMAKE
proc CMDDELETE; \COMMAND: DELETE
int FLAG,FILENO;
begin
CHKFILE;
NAME("BAK",ACTDEV);
FLAG:= false;
FILENO:= LOOKUP(0);
while FILENO#NONE do
begin
CLEAR(FILENO);
FLAG:= true;
FILENO:= LOOKUP(FILENO+1);
end;
if FLAG then
begin
if VERIFY then WRTDIR else RDDIR(LOCDEV);
end
else ERROR("NO SUCH FILES FOUND");
end; \CMDDELETE
proc CMDSAVE; \COMMAND: SAVE
\SAVE THE CURRENT MEMORY IMAGE. NOTE THAT PART OF IT MAY BE IN SCRATCH.SYS
int SIZE, BLOCK, A;
begin
CHKFILE;
NAME("SAV",ACTDEV);
if not SWAPFLG then
begin
TXT("SAVED AREA MAY NOT BE VALID");
if not VERIFY then REBEGIN;
end;
BLOCK:= RESERVE(256);
FREAD(SYSDEV,SWPBLK(0),BLOCK,1); \GET SYSPAG FROM SCRATCH.SYS
if ARG1#NONE then
begin
if ARG2=NONE then
ERROR("NEED ENDING ADDRESS");
if ARG1 >= ARG2 then \%%%
ERROR("ILLEGAL ADDRESS RANGE");
A:= BLOCK + USRMEM - SYSPAG;
A(0):= ARG1;
SIZE:= (ARG2-ARG1)/256 +1; \SIZE IN BLOCKS OF .SAV FILE
A:= BLOCK + PROSIZ - SYSPAG; \ NOT INCLUDING SYSPAG
A(0):= SIZE;
FWRITE(SYSDEV,SWPBLK(0),BLOCK,1);
end;
A:= BLOCK + PROSIZ - SYSPAG;
SIZE:= A(0) +1; \SIZE IN BLOCKS INCLUDING SYSPAG
CHKDIR(LOCDEV);
if FIND(SIZE)<SIZE then ERROR("NOT ENOUGH SPACE ON THAT UNIT");
LASBLK:= FIRBLK+SIZE-1;
ENTER; \RECORD .SAV FILE IN THE DIRECTORY
WRTDIR;
SYSPAG(INFLG):= NOFILE;
SYSPAG(INNO):= FLNO;
SYSPAG(INUNT):= LOCDEV;
FSAVE(LOCDEV,FIRBLK);
\This last statement does not return directly. It loads SCRATCH.SYS into
\ memory then writes the .SAV file. It restarts Apex with a "re-entry"
\ condition which ultimately runs FIXSAV.
end; \CMDSAVE
\----------------------------------------------------------------------\
proc OPENOT;
\IF SWITCH IS "R", THEN OPEN EXISTING FILE ELSE OPEN A SUITABLE TENTATIVE
\ AS AN OUTPUT FILE FOR THE USER. USE THE NAME IN "LOCNAM".
int FILENO,SIZE,TARGSIZ,MINSIZ;
begin
if LOCNAM(0)=SP then return;
CHKDIR(LOCDEV);
if SWITCH=^R then
begin
\(NOTE THAT THE FILE MAY BE WRITTEN EVEN IF IT IS NOT CLOSED)
FILENO:= LOOKUP(0);
if FILENO=NONE then FILERR;
PUT16(FDATE, FILENO, SYSDAT);
WRTDIR;
OTLBLK(0):= GET16(FBLK,FILENO); \%%%
OTHBLK(0):= GET16(LBLK,FILENO); \%%%
end
else begin
\if INSIZE>0 then TARGSIZ:= INSIZE+(INSIZE/2)+10
\else TARGSIZ:= (GET16(LEMBLK,0) - GET16(FEMBLK,0) + 1) /2;
MINSIZ:= 1;
if (SPECIAL&2) & (INSIZE>0) then MINSIZ:= INSIZE+1; \IF SIZE LIMIT
if ARG1#NONE then [MINSIZ:= ARG1; TARGSIZ:= MINSIZ];
\SIZE:= FIND(TARGSIZ);
SIZE:= FIND(32767); \USE THE BIGGEST AVAIL--THE HELL WITH BISECTION
ENTER;
if SIZE<MINSIZ then ERROR("OUT FILE IS TOO SMALL");
WRTDIR;
OTLBLK(0):= FIRBLK; \%%%
OTHBLK(0):= LASBLK; \%%%
FILENO:= FLNO;
end;
SYSPAG(OTFLG):= SETUP;
SYSPAG(OTNO):= FILENO;
SYSPAG(OTUNT):= LOCDEV;
TXT("OUTFILE: "); PRTDEV(FILENO); CROUT;
PUTDIR(DIRDEV,true); \UPDATE BACKUP DIRECTORY
end; \OPENOT
proc OPENIN; \OPEN USER'S INPUT FILE
int FILENO;
begin
\OPEN USER'S INPUT FILE
if LOCNAM(0)=SP then return;
CHKDIR(LOCDEV);
FILENO:= LOOKUP(0);
if FILENO=NONE then FILERR;
INLBLK(0):= GET16(FBLK,FILENO); \%%%
INHBLK(0):= GET16(LBLK,FILENO); \%%%
SYSPAG(INFLG):= SETUP;
SYSPAG(INNO):= FILENO;
SYSPAG(INUNT):= LOCDEV;
INSIZE:= GET16(LBLK,FILENO) - GET16(FBLK,FILENO) +1;
INDATE:= GET16(FDATE,FILENO);
TXT(" INFILE: "); PRTDEV(FILENO); CROUT;
end; \OPENIN
proc CMDOPEN(DEFO,DEFI); \COMMAND: OPEN
\"@" means replace with another extension. If the operator doesn't type one in,
\ then use the default extension (set by "SET"). If the default extension is
\ "@@@", then use the system-wide default extension.
addr DEFO,DEFI,OUTNAM;
int I,OUTDEV,INFL,OTFL, FLIPFL, T, GOTFL;
begin
OUTNAM:= RESERVE(11);
if DEFO(0)=SP & DEFI(0)=SP then return;
if CHAR#SP then return; \("CHKFILE" IS NOT USED BECAUSE OF "PNTDIR", ETC.)
NEXT; \SKIP THE SPACE AFTER "OPEN"
OTFL:= false; INFL:= false;
GOTFL:= CHAR=SP;
NAME("@@@",ACTDEV);
if GOTFILE ! GOTFL then OTFL:= true;
FLIPFL:= CHAR=^>;
if CHAR=^< ! FLIPFL then
begin \GET INPUT FILE NAME
MOVENAME(LOCNAM, OUTNAM);
OUTDEV:= LOCDEV;
NEXT;
GOTFL:= CHAR=SP;
NAME("@@@",ACTDEV);
if GOTFILE ! GOTFL then INFL:= true;
end
else begin \INFILE = OUTFILE
MOVENAME(LOCNAM, OUTNAM);
OUTDEV:= LOCDEV;
if DEFO(0)#^@ then
for I:= 0,2 do OUTNAM(I+8):= DEFO(I);
INFL:= true;
OTFL:= true;
end;
if FLIPFL then
begin \FLIP (SWAP) INPUT AND OUTPUT FILES
T:= INFL; INFL:= OTFL; OTFL:= T;
T:= LOCDEV; LOCDEV:= OUTDEV; OUTDEV:= T;
for I:= 0,10 do
[T:= LOCNAM(I); LOCNAM(I):= OUTNAM(I); OUTNAM(I):= T];
end;
if LOCNAM(8)=^@ then \GET INFILE EXTENSION
if DEFI(0)#^@ then for I:= 0,2 do LOCNAM(8+I):= DEFI(I)
else for I:= 8,10 do LOCNAM(I):= RNAM(I);
if INFL & (DEFI(0)#SP) then OPENIN;
if OUTNAM(8)=^@ then \GET OUTFILE EXTENSION
if DEFO(0)#^@ then for I:= 0,2 do OUTNAM(8+I):= DEFO(I)
else for I:= 8,10 do OUTNAM(I):= RNAM(I);
MOVENAME(OUTNAM, LOCNAM);
LOCDEV:= OUTDEV;
if OTFL & (DEFO(0)#SP) then OPENOT;
end; \CMDOPEN
proc CMDCLOSE; \COMMAND: CLOSE
int I,FL,RSAV,FILENO;
begin
ACTDEV:= SYSPAG(OTUNT); \GET OUTPUT FILE UNIT NUMBER
LOCDEV:= ACTDEV;
CHKDIR(ACTDEV);
FL:= SYSPAG(OTNO);
if FSTAT(FL)=TENTATIVE then
begin
MOVENAME(FNAME +FL*11, LOCNAM);
FILENO:= LOOKUP(0);
if FILENO#NONE then
begin
\RESOLVE THE COLLISION
RSAV:= FILENO;
LOCNAM(8):= ^B; LOCNAM(9):= ^A; LOCNAM(10):= ^K;
FILENO:= LOOKUP(0);
if FILENO#NONE then CLEAR(FILENO);
TXT("BACKING: "); PRTDEV(RSAV); CROUT;
I:= RSAV*11+8;
FNAME(I):= ^B;
FNAME(I+1):= ^A;
FNAME(I+2):= ^K;
end;
end
else if FSTAT(FL)#REPLACE then
begin
TXT("OUTPUT FILE NOT OPEN
");
return;
end;
PUT16(LBLK, FL, OTHBLK(0));
CLOFIL(FL,true);
WRTDIR;
end; \CMDCLOSE
\----------------------------------------------------------------------\
proc CMDLIST; \COMMAND: LIST
int CHAR, DEV, BLK, HBLK, SIZ, I;
addr BUFFER;
begin
CHKFILE;
CMDOPEN(" ","@@@");
if SYSPAG(INFLG)#SETUP then FILERR;
\(DISK BUFFERING IS DONE THIS WAY TO AVOID TYING UP MEMORY WITH AN INPUT BUFFER)
DEV:= SYSPAG(INUNT);
BLK:= INLBLK(0);
HBLK:= INHBLK(0);
BUFFER:= RESERVE(4*BLKSIZ);
OPENI(1);
LINECTR:= 1;
loop begin
SIZ:= 4; \DON'T READ BEYOND END OF UNIT
if HBLK-BLK < 3 then SIZ:= HBLK -BLK +1;
FREAD(DEV, BLK, BUFFER, SIZ);
BLK:= BLK+4;
for I:= 0,1023 do
begin
CHAR:= BUFFER(I);
if CHAR>=$20 then CHOUT(0,CHAR) \(FOR SPEED)
else case CHAR of
CR: CROUTX;
LF: ; \IGNORE THE DAMN THINGS
FF: [CROUTX; CROUTX; CROUTX]; \DON'T ERASE ANYTHING
EOF: quit
other CHOUT(0,CHAR);
end;
end;
CROUTX;
SYSPAG(OTFLG):= NOFILE;
SYSPAG(INFLG):= NOFILE;
end; \CMDLIST
proc CMDRENAME; \COMMAND: RENAME
\RENAME NAMEOLD TO BE NAMENEW NAMENEW<NAMEOLD NAMEOLD>NAMENEW
int I, T, FILENO, DEV, FLIPFL, GOTFL, COUNT;
addr NAMENEW, NAMEOLD, NAME2NEW, NAME2OLD;
begin
NAMENEW:= RESERVE(11);
NAMEOLD:= RESERVE(11);
NAME2NEW:= RESERVE(11);
NAME2OLD:= RESERVE(11);
CHKFILE;
NAME(RNAM+8,ACTDEV);
MOVENAME(LOCNAM, NAMENEW); \NAMENEW := LOCNAM
if (CHAR#^< & CHAR#^>) then ERROR("UNCLEAR SYNTAX");
FLIPFL:= CHAR=^>;
DEV:= LOCDEV;
NEXT;
GOTFL:= CHAR=SP;
NAME(RNAM+8,DEV);
MOVENAME(LOCNAM, NAMEOLD);
if DEV#LOCDEV then ERROR("CANNOT CHANGE UNIT");
if not GOTFL & not GOTFILE then ERROR("NEED FILE NAME"); \(SPACE IS OK)
if FLIPFL then
begin \SWAP (FLIP) OLD AND NEW
MOVENAME(NAMENEW, NAME2NEW);
MOVENAME(NAMEOLD, NAMENEW);
MOVENAME(NAME2NEW, NAMEOLD);
end;
COUNT:= 0;
MOVENAME(NAMEOLD, LOCNAM); \LOOKUP THE OLD, EXISTING NAME(S)
FILENO:= LOOKUP(0);
while FILENO#NONE do \FOR ALL OF THE OLD, EXISTING NAMES...
begin
COUNT:= COUNT+1;
\REPLACE ?'S IN THE NEW NAME WITH CORRESPONDING CHAR IN OLD NAME
MOVENAME(FNAME +FILENO*11, NAME2OLD); \GET THE EXISTING NAME
MOVENAME(NAMENEW, NAME2NEW);
for I:= 0,10 do
if NAME2NEW(I)=^? then NAME2NEW(I):= NAME2OLD(I);
\DON'T ALLOW: RENAME SAMENAME.SSS<*.*
MOVENAME(NAME2NEW, LOCNAM);
if LOOKUP(0)#NONE then ERROR("FILE NAME IS USED");
TXT(" RENAME: "); PRTDEV(FILENO); CROUT;
MOVENAME(NAME2NEW, FNAME +FILENO*11);
TXT(" TO BE: "); PRTDEV(FILENO); CROUT;
MOVENAME(NAMEOLD, LOCNAM); \LOOKUP THE OLD, EXISTING NAME(S)
FILENO:= LOOKUP(FILENO+1);
end;
if COUNT=0 then FORMERR;
if COUNT>=2 then
[if VERIFY then WRTDIR else DIRDEV:= $FF]
else WRTDIR;
end; \CMDRENAME
\----------------------------------------------------------------------\
proc CMDUNLOCK(BOOL); \COMMANDS: LOCK & UNLOCK
int BOOL; \UNLOCK IF TRUE
begin
while CHAR=SP do NEXT;
if NUMERIC then ACTDEV:= NUMIN;
MAXTBL(ACTDEV):= $7FFF; \ALLOW THE READ NO MATTER WHAT ????
CHKDIR(ACTDEV);
FLAGS(3):= BOOL; \SET FLAG AS WE WILL WANT IT
SYSPAG(LOKMSK):= SYSPAG(LOKMSK) ! BITS(ACTDEV); \UNLOCK FOR THIS WRITE
if MAXBLK<16 then PUT16(PMAXB, 0, 16); \FORCE MINIMUM SIZE
MAXTBL(DIRDEV):= $7FFF; \ALLOW THIS WRITE
PUTDIR(DIRDEV,false); \(ALL TO SET ONE BYTE)
RDDIR(ACTDEV); \SET "LOKMSK" (THE HARD WAY)
TXT("UNIT "); NUMOUT(ACTDEV); TXT(" IS ");
if FLAGS(3) then TXT("UNLOCKED") else TXT("WRITE LOCKED");
CROUT;
end; \CMDUNLOCK
proc CMDSUB; \COMMAND: SUB
int FILE, SIZE;
begin
NAME("SBD",ACTDEV);
LOCNAM(8):= ^S; \MAKE SURE IT'S A SUB-DIRECTORY
LOCNAM(9):= ^B;
LOCNAM(10):= ^D;
if GOTFILE then \IF WE'VE GOT A FILE (NOT JUST A SPACE) THEN
begin \ MOVE TO SUB-DIRECTORY
CHKDIR(LOCDEV);
FILE:= LOOKUP(0);
if FILE=NONE then ERROR("NO SUCH SUB-DIRECTORY");
OFFTBL(LOCDEV):= OFFTBL(LOCDEV) + GET16(FBLK,FILE);
SIZE:= GET16(LBLK,FILE) - GET16(FBLK,FILE) + 1;
MAXTBL(LOCDEV):= OFFTBL(LOCDEV) + SIZE; \SO WE CAN DIDDLE
RDDIR(LOCDEV); \NOW FORCE SIZE TO BE CORRECT
if SIZE#MAXBLK+1 then
begin
TXT("HEY! SIZE IS WRONG. I WILL FIX IT."); CROUT; \????
MAXTBL(LOCDEV):= OFFTBL(LOCDEV) + SIZE; \SO WE CAN DIDDLE
if FLAGS(3) then
begin
MAXBLK:= SIZE-1;
PUT16(PMAXB, 0, MAXBLK);
WRTDIR;
RDDIR(LOCDEV);
end
else begin
TXT("OOPS! I CAN'T, YOU LOCKED IT!"); CROUT;
end;
end;
TXT("THE DEED IS DONE. SIZE: ");
NUMOUT(MAXTBL(LOCDEV) - OFFTBL(LOCDEV)); CROUT;
end
else begin \RESTORE TO PARENT DIRECTORY
OFFTBL(LOCDEV):= 0;
RDDIR(LOCDEV);
MAXTBL(LOCDEV):= MAXBLK +1;
TXT("UNIT "); NUMOUT(LOCDEV); TXT(" RESET. SIZE: ");
NUMOUT(MAXTBL(LOCDEV) - OFFTBL(LOCDEV)); CROUT;
end;
end; \CMDSUB
\----------------------------------------------------------------------\
proc FIXSAV; \CLOSE THE .SAV FILE STARTED FROM "CMDSAVE"
\THIS PROCEDURE CANNOT BE CALLED DIRECTLY FROM "CMDSAVE" BECAUSE APEX MAY
\ NOT BE IN MEMORY WHEN THE .SAV FILE IS WRITTEN.
int FL;
begin
LOCDEV:= SYSPAG(INUNT);
CHKDIR(LOCDEV);
FL:= SYSPAG(INNO);
CLOFIL(FL,false); \(PACKING IS UNNECESSARY BECAUSE .SAV FILE
WRTDIR; \ IS PUT INTO THE FIRST BIGGEST EMPTY LOCATION
end; \FIXSAV
func LOOKER(DEV);
\A RECURSIVE ROUTINE TO SEARCH ALL SUB-DIRECTORIES ON A UNIT AND RETURN
\ THE FIRST BLOCK OF A FILE (RELATIVE TO THE DIRECTORY AT THE TIME OF CALL).
int DEV;
int FILE,HOLDAD,REPLY,FIRBLK,BASEAD;
addr HOLD,SBDNAM;
begin
LOCDEV:= DEV;
FILE:= LOOKUP(0);
if FILE#NONE then return GET16(FBLK,FILE);
\TRIVIAL CASE TAKEN CARE OF, SO GO ONE DEEPER
HOLD:= RESERVE(11);
MOVENAME(LOCNAM, HOLD);
SBDNAM:= "????????SBD";
HOLDAD:= OFFTBL(DEV);
FILE:= -1;
loop begin \LOOK FOR A SBD
MOVENAME(SBDNAM, LOCNAM);
FILE:= LOOKUP(FILE+1);
if FILE=NONE then [REPLY:= NONE; quit];
\FOUND ONE SO SUB TO IT
BASEAD:= GET16(FBLK,FILE);
OFFTBL(DEV):= BASEAD + OFFTBL(DEV);
RDDIR(DEV);
\AND RECURSE
MOVENAME(HOLD, LOCNAM);
FIRBLK:= LOOKER(DEV);
if FIRBLK#NONE then [REPLY:= FIRBLK+BASEAD; quit];
OFFTBL(DEV):= HOLDAD;
RDDIR(DEV);
end;
OFFTBL(DEV):= HOLDAD;
RDDIR(DEV);
MOVENAME(HOLD, LOCNAM);
return REPLY;
end; \LOOKER
proc DOCMD(BLK); \EXECUTE A .CMD FILE BEGINNING AT BLOCK "BLK"
int BLK;
int I,J,K,CH,ARGSIZ;
addr BLOCK,ARG;
proc INSERT(CH);
int CH;
begin
if CH=LF then return;
if I>254 then ERROR(".CMD FILE IS TOO BIG");
CMDBUF(I):= CH;
I:= I+1;
end; \INSERT
begin \DOCMD
ARG:= RESERVE(80);
while CHAR=SP do NEXT; \("1:#" WON'T WORK OTHERWISE)
I:= 0;
while CHAR#CR do \GET ARGUMENT (IF ANY) FROM COMMAND LINE
begin
if I<79 then [ARG(I):= CHAR; I:= I+1];
NEXT;
end;
ARGSIZ:= I-1;
BLOCK:= RESERVE(256);
FREAD(ACTDEV,BLK,BLOCK,1); \READ IN .CMD FILE
J:= 0; I:= 0;
repeat begin
CH:= BLOCK(J); J:= J+1;
case CH of
^#: for K:= 0,ARGSIZ do INSERT(ARG(K)); \INSERT ARGUMENT
^^: begin \INSERT CTRL CHAR
CH:= BLOCK(J); J:= J+1;
if CH>=$40 then INSERT(CH-$40);
end
other INSERT(CH);
end
until CH=EOF;
SYSPAG(CMDMODE):= true;
CMDPTR(0):= CMDBUF;
REBEGIN;
end; \DOCMD
proc RUN(BLK); \RUN A .SAV FILE BEGINNING AT BLOCK "BLK"
int BLK;
int FIRBLK,I,DEV;
addr BLOCK,DEFO,DEFI;
begin
if BLK=NONE then return;
BLOCK:= RESERVE(256);
DEFO:= RESERVE(3);
DEFI:= RESERVE(3);
FREAD(ACTDEV,BLK,BLOCK,1);
for I:= 0,2 do [DEFO(I):= BLOCK(DEXTO+I)];
for I:= 0,2 do [DEFI(I):= BLOCK(DEXTI+I)];
SPECIAL:= BLOCK(DEFAUL);
DEV:= ACTDEV;
ACTDEV:= RDEV;
CMDOPEN(DEFO,DEFI);
CROUT;
FRUN(DEV,BLK); \(NEVER RETURNS)
end; \RUN
\======================================================================\
begin \MAIN
BITS:= [$01,$02,$04,$08,$10,$20,$40,$80];
MOSTR:= "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
DIRLEN:= [24, 48, 48, 6, 6, 24, 8, 16, 16, 48, 4];
CHAR:= CR;
SYSPAG:= $0400; \LOCATION OF RESIDENT SYSTEM PAGE
USRMEM:= $432; \ABSOLUTE ADDRESSES IN SYSTEM PAGE
PROSIZ:= $436;
SYSBLK:= $502;
SWPBLK:= $506;
OTLBLK:= $556;
OTHBLK:= $55A;
INLBLK:= $562;
INHBLK:= $566;
MAXTBL:= $0586;
OFFTBL:= $05C6;
CONWID:= 80; \GET CONSOLE DIMENSIONS
CONHT:= 24;
CMDPTR:= $698;
CMDBUF:= $6A8;
BLKSIZ:= 256; \SIZE OF A BLOCK IN BYTES
DIRBLK:= 9; \LOCATION OF DIRECTORY BLOCK
DIRSIZ:= 4; \SIZE OF DIRECTORY IN "BLKSIZ" BLOCKS
BACKBLK:= DIRBLK + DIRSIZ; \LOCATION OF BACKUP DIRECTORY
USERBLK:= BACKBLK + DIRSIZ; \START OF USER FILE SPACE
MAXFL:= 95; \SELECT SO THAT DIRSIZ IS RIGHT
\RESERVE THE ARRAYS
II:= (MAXFL+1)*2;
\BLOCKS 0-2
FNAME:= RESERVE(8*BLKSIZ); \%%%
FSTAT:= FNAME + ((MAXFL+1)*11);
FBLK:= FSTAT + (MAXFL+1);
LBLK:= FBLK + (II);
\BLOCK 3
FEMBLK:= LBLK + (II);
LEMBLK:= FEMBLK + (24);
STAB:= LEMBLK + (24);
NUMVAL:= STAB + (MAXFL+1);
DIRCHG:= NUMVAL + (1);
PRDEV:= DIRCHG + (1);
PMAXB:= PRDEV + (1);
DFNAME:= PMAXB + (2);
UNUSED:= DFNAME + (11);
TITLE:= UNUSED + (16);
UNUSED:= TITLE + (64);
APEXID:= UNUSED + (24);
VOLUME:= APEXID + (4);
DIRDAT:= VOLUME + (2);
UNUSED:= DIRDAT + (2);
FDATE:= UNUSED + (32);
FLAGS:= FDATE + (II);
\FLAGS + (16);
\NON-DIR ARRAYS:
LOCNAM:= RESERVE(11);
RNAM:= RESERVE(11);
OPENI(0); OPENO(0);
\There are these ways in which this program may have been entered:
\A) Cold reboot from power off. In that case we expect that the
\ system will have loaded with an invalid system date. The flag COLD
\ is used to identify this state.
\B) We could have been re-entered after an error dropout (REBEGIN). In this
\ case only, the RERUN flag will be true.
\C) We could have been entered from the resident code, with or
\ without a reload. The resident code provides the flag SYSENF (system entry
\ flag) to distinguish these:
\ RELOAD=$FC == reloaded from scratch (no history)
\ RENTER=$FD == re-entered without saving the swap space.
\ SAVER=$FE == reloaded after saving swap space into "SCRATCH.SYS".
\ FSAVE=$FF == reloaded after writing a .SAV file to disk.
\ FASAVE=$F0 == reloaded after writing "SYSTEM.SYS"
\IS THIS A COLD START REBOOT?
COLD:= not (SYSPAG(DATOFF) & SYSPAG(DATOF1));
COLD:= (SYSPAG(DATOF2) # (COLD&$FF));
if COLD then
begin
CHOUT(0,FF);
TXT("
A P E X
/ \
/ \
BY
COMPUTER APPLICATIONS
4334 EAST 17TH AVENUE
DENVER COLORADO 80220
TYPE ^"HELP^" FOR INSTRUCTIONS
");
end
else CROUT;
if not RERUN then \NOT AN ERROR RESTART--SHOW WE'RE BACK IN APEX
[TXT("-- APEX, V1.8x18 --"); CROUT];
CMDNEW(SYSPAG(SYSUNT));
SYSDAT:= SYSPAG(DATOFF) + SWAP(SYSPAG(DATOF1));
if SYSPAG(SYSENF) = RELOAD then
[TXT("RELOADED FROM UNIT "); NUMOUT(SYSDEV); CROUT];
if SYSPAG(OTFLG)=CLOSED then \CLOSE ANY NEW TENTATIVES LYING AROUND
[CMDCLOSE; SYSPAG(OTFLG):= NOFILE];
SWAPFLG:= false;
if SYSPAG(SYSENF)=SAVEIN then \WE HAVE A .SAV FILE TO UPDATE
[FIXSAV; SWAPFLG:= true]; \OUR SWAP AREA MUST BE VALID
if SYSPAG(SYSENF)=SWAPIN then
SWAPFLG:= true;
SYSPAG(OTFLG):= NOFILE; SYSPAG(INFLG):= NOFILE; \ERASE ANY OPEN FILES
\NOW CHECK FOR UNITS NEEDING ATTENTION:
\REMOVED - SEE RDDIR
\++for II:= 0,7 do if (SYSPAG(UNTUPD) & BITS(II))#0 then RDDIR(II);
if COLD then
begin \IF COLD START, RUN "STARTUP.CMD"
COLD:= false;
SYSPAG(SYSENF):= 0;
ACTDEV:= SYSDEV;
FILENO:= FINDFL(SYSDEV,"STARTUP CMD");
if FILENO#NONE then DOCMD(GET16(FBLK,FILENO));
end;
loop begin \COMMAND DECODER
SWITCH:= SP;
SPECIAL:= 1;
INSIZE:= 0;
INDATE:= SYSDAT; \DEFAULT DATE
TXT("APX>");
\ OPENI(0);
NEXT;
NAME("CMD",SYSDEV);
if GOTFILE then
begin \IS COMMAND
ACTDEV:= LOCDEV;
if SWITCH#^E & LOCNAM(8)=^C & LOCNAM(9)=^M & LOCNAM(10)=^D then
begin
FILENO:= LOOKUP(0);
if FILENO#NONE then DOCMD(GET16(FBLK,FILENO));
end;
LOCNAM(8):= ^S; \FORCE IT TO A ".SAV" FILE
LOCNAM(9):= ^A;
LOCNAM(10):= ^V;
FILENO:= LOOKUP(0);
if FILENO#NONE then RUN(GET16(FBLK,FILENO)); \(NEVER RETURNS)
if DRVSET then
begin \TRY A DEEP SEARCH ON THE SYSTEM UNIT
if ACTDEV#SYSDEV then FILERR;
RUN(LOOKER(ACTDEV));
FILERR;
end;
\NOT A VALID FILE NAME SO IT MUST BE A COMMAND
ACTDEV:= RDEV;
HASH:= LOCNAM(0) + SWAP(LOCNAM(1));
case HASH of
17735\GE\: CMDGET;
21587\ST\: CMDSTART(true);
22355\SW\: CMDSTART(false);
\ 21335\\WS\\: CMDWS;
17742\NE\: CMDNEW(SYSPAG(SYSUNT));
22867\SY\: CMDSYS;
18771\SI\: CMDSIZE;
16708\DA\: CMDDATE;
18756\DI\: CMDDIR;
17474\BD\: CMDBD;
18772\TI\: CMDTITLE;
17754\ZE\: CMDZERO;
17988\DF\: CMDDF;
20292\DO\: CMDDO(true);
20302\NO\: CMDDO(false);
16717\MA\: CMDMAKE;
$5153\SQ\: CMDSQ;
17732\DE\: CMDDELETE;
16723\SA\: CMDSAVE;
20559\OP\: CMDOPEN("@@@","@@@");
19523\CL\: CMDCLOSE;
18764\LI\: CMDLIST;
17746\RE\: CMDRENAME;
20300\LO\: CMDUNLOCK(false);
20053\UN\: CMDUNLOCK(true);
21843\SU\: CMDSUB
other [CHOUT(0,BEL); TXT("I BEG YOUR PARDON?"); DOREBEGIN];
end;
end;
end; \MAIN
LOCK(true);
21843\SU\: CMDSUB
other [CHOUT(0,BEL); TXT("I BEG YOUR PARDON?"); DOREBEGIN];
end;
end;
end